package util

import (
	"errors"
	"fmt"
	"reflect"
)

// 检查函数参数是否匹配
func CheckFuncArgs(fun interface{}, args ...interface{}) error {
	if fun == nil {
		return errors.New("函数为 nil")
	}
	// 获取函数的反射类型
	funType := reflect.TypeOf(fun)

	// 确保传入的是函数
	if funType.Kind() != reflect.Func {
		return fmt.Errorf("非函数类型，而是 %v", funType.Kind())
	}

	// 获取要传入的参数数量
	numArgs := len(args)

	// 处理固定参数函数
	if !funType.IsVariadic() {
		// 检查参数个数是否匹配
		if numArgs != funType.NumIn() {
			return fmt.Errorf("函数参数个数不匹配：需要 %d 个参数，实际传入 %d 个", funType.NumIn(), numArgs)
		}

		// 逐个检查参数类型
		for i := 0; i < numArgs; i++ {
			expectedType := funType.In(i)
			actualType := reflect.TypeOf(args[i])

			// 检查类型是否匹配
			if !actualType.AssignableTo(expectedType) {
				return fmt.Errorf("函数第 %d 个参数类型不匹配：期望 %v，实际 %v", i+1, expectedType, actualType)
			}
		}
		return nil
	}

	// 处理可变参数函数
	minArgs := funType.NumIn() - 1 // 可变参数函数至少需要 NumIn()-1 个参数

	// 检查参数个数是否合法
	if numArgs < minArgs {
		return fmt.Errorf("函数参数个数不足：可变参数至少需要 %d 个参数，实际传入 %d 个", minArgs, numArgs)
	}

	// 检查固定参数部分
	for i := 0; i < minArgs; i++ {
		expectedType := funType.In(i)
		actualType := reflect.TypeOf(args[i])

		if !actualType.AssignableTo(expectedType) {
			return fmt.Errorf("函数第 %d 个参数类型不匹配：期望 %v，实际 %v", i+1, expectedType, actualType)
		}
	}

	// 检查可变参数部分
	if numArgs > minArgs {
		variadicType := funType.In(minArgs).Elem() // 获取可变参数的元素类型

		for i := minArgs; i < numArgs; i++ {
			actualType := reflect.TypeOf(args[i])

			if !actualType.AssignableTo(variadicType) {
				return fmt.Errorf("函数可变参数 %d 类型不匹配：期望 %v，实际 %v", i+1, variadicType, actualType)
			}
		}
	}
	return nil
}

// 判断变量是否为函数且返回值包含error类型
func IsFuncReturnError(fun interface{}) bool {
	if fun == nil {
		return false
	}
	// 获取变量的反射类型
	funType := reflect.TypeOf(fun)
	// 检查是否为函数类型
	if funType.Kind() != reflect.Func {
		return false
	}

	// 判断返回参数数量
	if funType.NumOut() != 1 {
		return false
	}
	// 判断返回参数是否实现了error接口
	return funType.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem())
}
